//
// Created by lz on 2021/2/7.
//

#include "base/Logging.h"


#include "base/Timestamp.h"
#include "base/TimeZone.h"
#include "base/CurrentThread.h"



#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sstream>

namespace lzweb
{
	__thread char t_errnobuf[512];
	__thread char t_time[64];
	__thread time_t t_lastSecond;

	const char* strerror_tl(int savedErrno)
	{
		// return string describing error number
		return strerror_r(savedErrno,t_errnobuf, sizeof(t_errnobuf));
	}

	Logger::LogLevel initLogLevel()
	{

		if(getenv("MUDUO_LOG_TRACE"))
			return Logger::TRACE;
		else if (getenv("MUDUO_LOG_DEBUG"))
			return Logger::DEBUG;
		else
			return Logger::INFO;
	}

	Logger::LogLevel g_logLevel = initLogLevel();

	const char* LogLevelName[Logger::NUM_LOG_LEVELS] =
		{
		"TRACE ",
		"DEBUG ",
		"INFO  ",
		"WARN  ",
		"ERROR ",
		"FATAL ",
		};

	// helper class for known string length at compile time
	class T
	{
	 public:
		T(const char* str, unsigned  len)
		:str_(str),len_(len)
		{
			assert(strlen(str) == len_);
		}
		const char* str_;
		const unsigned len_;
	};

	inline LogStream& operator<<(LogStream& s, T v)
	{
		s.append(v.str_,v.len_);
		return s;
	}

	inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v)
	{
		s.append(v.data_,v.size_);
		return s;
	}

	void defaultOutput(const char* msg, int len)
	{
		size_t n = fwrite(msg, 1, len,stdout);
		//FIXME check n
		(void) n;
	}


	void defaultFlush()
	{
		fflush(stdout);
	}

	Logger::OutputFunc  g_output = defaultOutput;
	Logger::FlushFunc  g_flush = defaultFlush;
	TimeZone g_logTimeZone;
} // namespace lzweb

using namespace lzweb;


//构造函数中执行了将大部分日志信息输入到stream_中
Logger::Impl::Impl(LogLevel level, int old_errno, const SourceFile& file, int line)
:time_(TimeStamp::now()),stream_(),level_(level),line_(line),basename_(file)
{
	formatTime();
	CurrentThread::tid();
	stream_<<T(CurrentThread::tidString(),CurrentThread::tidStringLength());
	stream_<<T(LogLevelName[level],6);

	if(old_errno != 0)
	{
		stream_<< strerror_tl(old_errno) <<" (errno="<<old_errno<<") ";
	}

}
// 格式化输入当前的时间
void Logger::Impl::formatTime()
{
	int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch();
	time_t seconds = static_cast<time_t>(microSecondsSinceEpoch / TimeStamp::kMicroSecondsPerSecond);
	int microseconds = static_cast<int>(microSecondsSinceEpoch % TimeStamp::kMicroSecondsPerSecond);

	if(seconds != t_lastSecond)
	{
		t_lastSecond = seconds;

		struct tm tm_time;
		if(g_logTimeZone.valid())
		{
			tm_time = g_logTimeZone.toLocalTime(seconds);
		}
		else
		{
			gmtime_r(&seconds,&tm_time);  //FIXME TimeZone::fromUtcTime
		}

		int len = snprintf(t_time, sizeof(t_time),"%4d%02d%02d %02d:%02d:%02d",
			tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday,
			tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
		assert( len == 17);
		(void) len;
	}

	if(g_logTimeZone.valid())
	{
		Fmt us(".%06d ",microseconds);

		assert(us.length() == 8);
		stream_ << T(t_time,17)<<T(us.data(),8);
	}
	else
	{
		Fmt us(".%06dZ ",microseconds);
		assert(us.length() == 9);
		stream_ << T(t_time, 17)<<T(us.data(),9);
	}
}

void Logger::Impl::finish()
{
	stream_<<" - "<<basename_<<':'<<line_<<'\n';
}

Logger::Logger(SourceFile file, int line)
:impl_(INFO,0,file,line)
{
}

Logger::Logger(SourceFile file, int line, LogLevel level, const char* func)
:impl_(level,0,file,line)
{
}
Logger::Logger(Logger::SourceFile file, int line, Logger::LogLevel level)
:impl_(level,0,file,line)
{
}

Logger::Logger(SourceFile file, int line, bool toAbort)
:impl_(toAbort? FATAL:ERROR,errno,file,line)
{
}

Logger::~Logger()
{
	impl_.finish();
	const LogStream::Buffer& buf(stream().buffer());

	//最终在这里把所有的数据输出到外部
	g_output(buf.data(),buf.length());
	if(impl_.level_ == FATAL)
	{
		g_flush();
		abort();
	}
}

void Logger::setLogLevel(LogLevel level)
{
	g_logLevel = level;
}

void Logger::setOutput(OutputFunc out)
{
	g_output = out;
}

void Logger::setFlush(FlushFunc flush)
{
	g_flush = flush;
}

void Logger::setTimeZone(const TimeZone& tz)
{
	g_logTimeZone = tz;
}



